package com.apes.framework.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.TimeUnit;

/**
 * 功能：分布式锁
 *
 * @author xul
 * @create 2020-06-16 16:08
 */
@Component
public class DistributedLock {
    protected static ThreadLocal<Queue<String>> locks = new ThreadLocal<>();

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 加锁成功执行lockSuccessCallback，否则执行lockFailureCallback
     * @param lockId  锁Id
     * @param millisecond 加锁时间（单位：毫秒）
     * @param lockSuccessCallback 加锁成功执行的回调
     * @param lockFailureCallback 加锁失败执行的回调
     */
    public void lock(String lockId, long millisecond, Callback lockSuccessCallback, Callback lockFailureCallback) {
        if (lockSuccessCallback == null) {
            throw new RuntimeException("加锁成功后的回调方法不允许为空！");
        }
        boolean lockSuccess = false;
        try {
            lockSuccess = lock(lockId, millisecond);
            if (lockSuccess) {
                lockSuccessCallback.execute();
            } else if (lockFailureCallback != null) {
                lockFailureCallback.execute();
            }
        } finally {
            if (lockSuccess) unlock(lockId);
        }
    }

    public boolean existLock(String lockId) {
        Object lock = redisTemplate.opsForValue().get(lockId);
        return lock != null && "lock".equals(lock);
    }

    /**
     * 获得锁
     */
    public boolean lock(String lockId, long millisecond) {
        Boolean success = redisTemplate.opsForValue().setIfAbsent(lockId, "lock", millisecond, TimeUnit.MILLISECONDS);
        return success != null && success;
    }

    /**
     * 释放锁
     */
    public void unlock(String lockId) {
        redisTemplate.delete(lockId);
    }


    /**
     * 增加一个元索
     */
    public static void add(String lockId) {
        Queue<String> queue = getQueue();
        queue.add(lockId);
    }

    public static Queue<String> getQueue() {
        Queue<String> queue = locks.get();
        if (queue == null) {
            queue = new LinkedList<>();
            locks.set(queue);
        }
        return queue;
    }

    /**
     * 移除并返问队列头部的元素
     **/
    public static String poll() {
        Queue<String> queue = getQueue();
        if (queue == null || queue.isEmpty()) {
            return null;
        }
        return queue.poll();
    }

    /**
     * 调用remove方法能有效的杜绝内存泄露问题
     */
    public static void remove() {
        locks.remove();
    }

    @FunctionalInterface
    public interface Callback {
        @Nullable
        void execute();
    }
}
